package com.feinno.urcs.group.interop.service;

import com.feinno.cpim.CpimMessage;
import com.feinno.urcs.content.MimeType;
import com.feinno.urcs.dns.EnumService;
import com.feinno.urcs.group.GroupConfiguration;
import com.feinno.urcs.group.api.*;
import com.feinno.urcs.group.entity.*;
import com.feinno.urcs.group.interop.FXGroupMessageInterOpService;
import com.feinno.urcs.group.interop.entity.FetionFileMessageArgs;
import com.feinno.urcs.group.interop.entity.FetionTextMessageArgs;
import com.feinno.urcs.group.interop.entity.InteropFileMessageArgs;
import com.feinno.urcs.group.interop.entity.InteropTextMessageArgs;
import com.feinno.urcs.group.log.MessageContentType;
import com.feinno.urcs.group.log.MessageDirection;
import com.feinno.urcs.group.pctask.task.AndPcGroupMsgArgs;
import com.feinno.urcs.group.siptask.task.GroupFileTransferArgs;
import com.feinno.urcs.group.siptask.task.GroupMessageArgs;
import com.feinno.urcs.group.siptask.task.GroupTaskEvents;
import com.feinno.urcs.group.util.CpimUtils;
import com.feinno.urcs.group.util.DateUtils;
import com.feinno.urcs.group.util.FileDownloadHttpClient;
import com.feinno.urcs.group.util.FileTypeJudgeUtils;
import com.feinno.urcs.profile.entity.ClientType;
import com.feinno.urcs.sip.UrcsSipFactory;
import com.feinno.urcs.storage.FileStream;
import com.feinno.urcs.storage.FileStreamService;
import com.feinno.urcs.types.MobileNo;
import com.feinno.util.DateUtil;
import com.feinno.util.StringUtils;
import org.helium.framework.annotations.FieldSetter;
import org.helium.framework.annotations.ServiceImplementation;
import org.helium.framework.annotations.ServiceSetter;
import org.helium.framework.annotations.TaskEvent;
import org.helium.framework.rpc.LegacyRpcService;
import org.helium.framework.task.TaskProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sip.address.SipURI;
import java.io.IOException;
import java.util.List;

/**
 * 给老飞信 互通使用, 用于接收飞信终端发送的消息,并转发到RCS 客户端.
 *
 * @author Li.Hongbo <lihongbo@feinno.com>
 */
@ServiceImplementation
@LegacyRpcService(serviceName = "GroupMessageRpc")
public class FXGroupMessageInterOpServiceImpl implements FXGroupMessageInterOpService {
	private static final Logger LOGGER = LoggerFactory.getLogger(FXGroupMessageInterOpServiceImpl.class);
	@ServiceSetter
	private GroupService groupService;
	@ServiceSetter
	private FXUserIndexService fxUserIndexService;
	@ServiceSetter
	private EnumService enumService;
	@ServiceSetter
	private GroupTerminalService groupTerminalService;
	@ServiceSetter
	private FileStreamService fileStreamService;

	@ServiceSetter
	private GroupMessageStorageService groupMessageStorageService;
	@TaskEvent(GroupTaskEvents.GROUP_SESSION_MODE_MESSAGE)
	private TaskProducer<GroupMessageArgs> messageTask;
	@TaskEvent(GroupTaskEvents.GROUP_FILE_TRANSFER)
	private TaskProducer<GroupFileTransferArgs> fileTransferTask;
	@TaskEvent(GroupTaskEvents.GROUP_FETION_MESSAGE_TEXT)
	private TaskProducer<FetionTextMessageArgs> fetionSendTextTask;
	@TaskEvent(GroupTaskEvents.GROUP_FETION_MESSAGE_FILE)
	private TaskProducer<FetionFileMessageArgs> fetionSendFileTask;
	@TaskEvent(GroupTaskEvents.GROUP_MESSAGE_TO_PC)
	private TaskProducer<AndPcGroupMsgArgs> andPcGroupMsgTask;

	@ServiceSetter
	private GroupMessageLogService groupMessageLogService;


	@FieldSetter("${FETION_NCFP_PATH}")
	private String fetion_ncfp_path;


	@FieldSetter("${FETION_HDS_URL}")
	private String fetion_hds_url;


	public FXGroupMessageInterOpServiceImpl() {
	}

	private static final String FETION_ClIENT_TYPE = "FETION";

	@Override
	public void sendText(InteropTextMessageArgs req) {
		// TODO 需要对消息内容,以及ContentType 做转换
		try {
			LOGGER.info(String.format("fX sendText start args=%s", req));
			GroupIndex index = groupService.getGroupIndex(req.getGroupId());

			SipURI groupUri = UrcsSipFactory.getAddressFactory().createSipURI(GroupConfiguration.INSTANCE.getGroupPrefix() + index.getGroupId(), GroupConfiguration.INSTANCE.getGroupDomain());
			MobileNo sender = MobileNo.parseFrom(req.getSender());
			CpimMessage cpim = null;

			if ("text/plain".equals(req.getContentType())) {
				cpim = CpimUtils.createCpim(req.getContent(), sender, groupUri, "text/plain;charset=UTF-8", true, DateUtil.getUTCNow());
			} else {
				throw new UnsupportedOperationException("unsupport type :" + req.getContentType());
			}

//			switch (req.getContentType()) {
//				case "text/plain":
//					cpim = CpimUtils.createCpim(req.getContent(), sender, groupUri, "text/plain;charset=UTF-8", true, DateUtil.getUTCNow());
//					break;
//				case "CLOUDFILE":
//					// 彩云文件共享
//					cpim = CpimUtils.createCpim(req.getContent(), sender, groupUri, "application/cloudfile+xml", true, DateUtil.getUTCNow());
//					break;
//				case "OUTCE":
//					// 表情商店
//					cpim = CpimUtils.createCpim(req.getContent(), sender, groupUri, "application/vemoticon+xml", true, DateUtil.getUTCNow());
//					break;
//				case "LOCATION":
//					// 地理位置
//					cpim = CpimUtils.createCpim(req.getContent(), sender, groupUri, "application/vnd.gsma.rcspushlocation+xml", true, DateUtil.getUTCNow());
//					break;
//
//				default:
//					throw new UnsupportedOperationException("unsupport type :" + req.getContentType());
//			}
			sendText(index.getGroupId(), sender, "message/cpim", cpim.getByteArray(), req.getContentType());
		} catch (Exception e) {
			LOGGER.error(String.format("fx SendText error args=%s", req.toJsonObject()), e);
		}

	}


	private void sendText(int groupId, MobileNo memberMobile, String contentType, byte[] content, String fetionMessageContentType) throws Exception {
		// 活跃客户端更新
		GroupMessageArgs args;
		GroupIndex index = groupService.getGroupIndex(groupId);
		GroupInfo info = groupService.getGroupInfo(index);
		if (null == info || info.getConversationId() == null) {
			LOGGER.warn("groupinfo is null or conversationId is null, groupid = {}", groupId);
			return;
		}
		List<GroupMember> membersTo = info.getMembers();
		long groupMessageStorageId = groupMessageStorageService.storageTextMessage(groupId, memberMobile, contentType, content, ClientType.NONE);

		groupMessageLogService.textMessageUpstreamLog(String.valueOf(groupMessageStorageId), memberMobile, info
				, FETION_ClIENT_TYPE, MessageDirection.UP, MessageContentType.parse(fetionMessageContentType), new String(content), DateUtils.getUTCNow());
		for (GroupMember memberTo : membersTo) {
			LOGGER.info(String.format("sendText  GroupText Group=%s, Mobile=%s", groupId, memberMobile));
			args = new GroupMessageArgs();
			args.setGroupId(groupId);
			args.setFromMobile(memberMobile);
			args.setToMobile(memberTo.getMobileNo());
			args.setContentType(contentType);
			args.setContent(content);
			args.setDomain(GroupConfiguration.INSTANCE.getDomain());
			args.setConversationId(info.getConversationId());
			args.setGroupMessageStorageId(groupMessageStorageId);
			args.setIsPc(false);
			args.setFromFetion(true);
			args.setSendTime(DateUtil.getUTCNow());
			SipURI uri = (SipURI) enumService.getSipURI(memberTo.getMobileNo());
			if (uri == null) {
				// 未开通融合通信
				LOGGER.error(String.format("sendText  uri is null  GroupId=%s, MobileNo=%s ", info.getGroupId(), memberTo));

				continue;
			} else {
				groupTerminalService.sendTextMessage(args);
			}
		}
	}


	@Override
	public void sendRichText(InteropFileMessageArgs args) {
// TODO 需要对消息内容,以及ContentType 做转换
		try {
			LOGGER.info(String.format("fX sendRichText start args=%s", args));
			GroupIndex index = groupService.getGroupIndex(args.getGroupId());
			GroupInfo groupInfo = groupService.getGroupInfo(index);
			if (null == groupInfo || groupInfo.getConversationId() == null) {
				LOGGER.warn("groupinfo is null or conversationId is null, groupid = {}", args.getGroupId());
				return;
			}
			MobileNo memberMobile = MobileNo.parseFrom(args.getSender());
			if ("text/location".equals(args.getContentType())) {
				CpimMessage cpim = CpimUtils.createCpim(args.getContent(), memberMobile, groupInfo.getGroupSipUri(), "application/vnd.gsma.rcspushlocation+xml", true, DateUtils.getUTCNow());
				sendText(index.getGroupId(), memberMobile, "message/cpim", cpim.getByteArray(), args.getContentType());
				return;
			}
			if ("text/outce".equals(args.getContentType())) {

				CpimMessage cpim = CpimUtils.createCpim(args.getContent(), memberMobile, groupInfo.getGroupSipUri(), "application/vemoticon+xml", true, DateUtils.getUTCNow());
				sendText(index.getGroupId(), memberMobile, "message/cpim", cpim.getByteArray(), args.getContentType());
				return;
			}


			List<GroupMember> members = groupInfo.getMembers();
			GroupFileInfo fileInfo = fillGroupFileInfo(args);
			int groupId = groupInfo.getGroupId();
			groupMessageLogService.fileMessageUpstreamLog(fileInfo.getTransferId(), memberMobile, groupInfo
					, FETION_ClIENT_TYPE, MessageDirection.UP, fileInfo, DateUtils.getUTCNow());
			String senderName = "";
			for (GroupMember member : members) {
				LOGGER.info(String.format("dispatch GroupFile Group=%s, fromMobile=%s, toMobile=%s", index.getGroupId(), memberMobile, member.getMobileNo()));

				sendFileToUE(groupId, memberMobile, fileInfo, member);
				sendFileToPC(memberMobile, fileInfo, index, groupInfo, senderName, member);

			}

		} catch (Exception e) {
			LOGGER.error(String.format("sendRichText error entity =%s", args.toString()), e);
		}
	}

	/**
	 * 这个主要吧图片从远端下载, 然后上传到rcs 的图片存储,得到GroupFileInfo 对象.
	 *
	 * @param args
	 */

	private GroupFileInfo fillGroupFileInfo(InteropFileMessageArgs args) throws IOException {
		GroupFileInfo fileInfo = null;
		String mimeFileType = null;
		switch (args.getContentType().toLowerCase()) {
			case "text/pic":    //单图片
				// 图片有缩略图, 需要先下载,上传原图, 然后下载缩略图.
				String filePostfix = FileTypeJudgeUtils.getFileTypeWithPostfix(args.getFileName());
				if (filePostfix.equals("jpg")) filePostfix = "jpeg";  // TODO  jpeg
				MimeType type = MimeType.parse("image", filePostfix);
				mimeFileType = type.getValue();
				fileInfo = createGroupFileInfo(mimeFileType, args, !StringUtils.isNullOrEmpty(args.getThumbnailUrl()));
				fileInfo.setContent(null); // 清理掉内容,解决瞬时 服务器内存
				break;
			case "text/audio": // 音频
				mimeFileType = "application/octet-stream";
				fileInfo = createGroupFileInfo(mimeFileType, args, !StringUtils.isNullOrEmpty(args.getThumbnailUrl()));
				break;
			case "text/video": // 视频
				mimeFileType = "application/octet-stream";
				fileInfo = createGroupFileInfo(mimeFileType, args, !StringUtils.isNullOrEmpty(args.getThumbnailUrl()));
				break;
			case "text/card": // 名片
				mimeFileType = "application/octet-stream";
				fileInfo = createGroupCardFileInfo(args);
				break;
			case "text/location": // 地理位置
				LOGGER.warn(String.format("location  need impl args=%s", args));
				break;

			case "text/ce": // 表情
				fileInfo = createGroupFileInfoCE(args);
				break;

			case "text/outce": //表情商店
//				fileInfo = createGroupFileInfoCE(args);
				LOGGER.warn(String.format("outce  need impl args=%s", args));
				break;
			default:
				break;
		}
		return fileInfo;

	}

	private void sendFileToPC(MobileNo memberMobile, GroupFileInfo groupFileInfo, GroupIndex index, GroupInfo
			groupInfo, String senderName, GroupMember member) {
		try {
			LOGGER.info("sendFileToPC groupFileInfo : {}", groupFileInfo.toJsonObject());
			AndPcGroupMsgArgs andPcGroupRichMsgArgs = new AndPcGroupMsgArgs();
			String fileName = groupFileInfo.getFileName().toLowerCase();
			if (fileName.endsWith("mp4") || fileName.endsWith("avi") || fileName.endsWith("mpeg")) {
				andPcGroupRichMsgArgs.setContentType(GroupMessageType.VIDEO);
				groupFileInfo.setPcMessageType(GroupMessageType.VIDEO);
			} else if (fileName.endsWith("amr") || fileName.endsWith("mp3") || fileName.endsWith("wav")) {
				andPcGroupRichMsgArgs.setContentType(GroupMessageType.AUDIO);
				groupFileInfo.setPcMessageType(GroupMessageType.AUDIO);

			} else if (fileName.endsWith("jpeg") || fileName.endsWith("gif") || fileName.endsWith("bmp") || fileName.endsWith("png") || fileName.endsWith("jpg")) {
				andPcGroupRichMsgArgs.setContentType(GroupMessageType.IMG);
				groupFileInfo.setPcMessageType(GroupMessageType.IMG);
			} else if (fileName.endsWith("vcf")) {
				andPcGroupRichMsgArgs.setContentType(GroupMessageType.CARD);
				groupFileInfo.setPcMessageType(GroupMessageType.CARD);
				andPcGroupRichMsgArgs.setContent(groupFileInfo.getContent());
			} else if (fileName.endsWith("location.xml")) {
				andPcGroupRichMsgArgs.setContentType(GroupMessageType.LOCATION);
				groupFileInfo.setPcMessageType(GroupMessageType.LOCATION);
			} else {
				andPcGroupRichMsgArgs.setContentType(GroupMessageType.FILE);
			}
			andPcGroupRichMsgArgs.setFileType(groupFileInfo.getFileType());
			andPcGroupRichMsgArgs.setFileName(groupFileInfo.getFileName());
			andPcGroupRichMsgArgs.setFileSize(groupFileInfo.getFileSize());
			andPcGroupRichMsgArgs.setGroupId(index.getGroupId());
			andPcGroupRichMsgArgs.setSender(memberMobile);
			andPcGroupRichMsgArgs.setSenderName(StringUtils.isNullOrEmpty(senderName) ? memberMobile.getMobile() : senderName);
			andPcGroupRichMsgArgs.setSubject(groupInfo.getSubject());
			andPcGroupRichMsgArgs.setConversationId(groupInfo.getConversationId());
			andPcGroupRichMsgArgs.setToMobile(member.getMobileNo());
			andPcGroupRichMsgArgs.setTimeLen(groupFileInfo.getTimelen());
			andPcGroupRichMsgArgs.setSendTime(DateUtil.getUTCNow());
			// TODO 获取文件HTTP下载地址
			if (groupFileInfo.getPcMessageType() == GroupMessageType.IMG ||
					groupFileInfo.getPcMessageType() == GroupMessageType.CARD ||
					groupFileInfo.getPcMessageType() == GroupMessageType.AUDIO ||
					groupFileInfo.getPcMessageType() == GroupMessageType.VIDEO) {
				String fileId = groupFileInfo.getTransferId();
				String url = GroupConfiguration.INSTANCE.getHttpDownloadUrl() + fileId;
				andPcGroupRichMsgArgs.setUrl(url);
			}
			andPcGroupRichMsgArgs.setDomain(groupInfo.getDomain());
			andPcGroupRichMsgArgs.setGroupAtMembers(groupFileInfo.getAtMembers());
			LOGGER.info("sendFileToPC andPcGroupRichMsgArgs : {}", andPcGroupRichMsgArgs.toJsonObject());
			andPcGroupMsgTask.produce(andPcGroupRichMsgArgs);
		} catch (Exception e) {
			LOGGER.warn("andPcGroupMsgTask error", e);
		}
	}

	private void sendFileToUE(int groupId, MobileNo memberMobile, GroupFileInfo groupFileInfo, GroupMember member) {
		GroupFileTransferArgs args = new GroupFileTransferArgs();
		args.setGroupId(groupId);
		args.setFromMobile(memberMobile);
		args.setToMobile(member.getMobileNo());
		args.setGroupFileInfo(groupFileInfo);
		args.setSendTime(DateUtil.getUTCNow());
		fileTransferTask.produce(args);
	}

	private GroupFileInfo createGroupCardFileInfo(InteropFileMessageArgs args) throws IOException {
		GroupFileInfo fileInfo = new GroupFileInfo();
		fileInfo.setFileName(StringUtils.isNullOrEmpty(args.getFileName()) ? "VCARD.vcf" : args.getFileName());
		fileInfo.setFileType(MimeType.AppOctStream.getValue());
		fileInfo.setAcceptType(MimeType.AppOctStream.getValue());
		fileInfo.setMessageType(GroupMessageType.FILE);
		fileInfo.setFileSize(args.getContent().length);
		uploadGroupFileContent(fileInfo, MimeType.AppOctStream.getValue(), args.getContent());
		return fileInfo;
	}

	/**
	 * 创建一个GroupFileInfo, 下载远端文件后上传到RCS 文件服务.并下载缩略图,
	 *
	 * @param fileType
	 * @param args
	 * @param hasThumbnail 是否需要下载缩略图
	 * @return
	 * @throws IOException
	 */
	private GroupFileInfo createGroupFileInfo(String fileType, InteropFileMessageArgs args, boolean hasThumbnail) throws IOException {
		GroupFileInfo fileInfo = new GroupFileInfo();
		fileInfo.setFileName(args.getFileName());
		fileInfo.setFileType(fileType);
		fileInfo.setAcceptType(fileType);
		fileInfo.setContentTransferEncoding("");

		if (hasThumbnail) {
			byte[] vidioThumbnailContent = FileDownloadHttpClient.getFile(replaceUrl(args.getThumbnailUrl()));
			fileInfo.setThumbnail(vidioThumbnailContent);
		}

		uploadGroupFileContent(fileInfo, fileType, replaceUrl(args.getUrl()));

		if (args.getTimelen() != 0) {
			fileInfo.setTimelen(args.getTimelen());
		}
		return fileInfo;
	}

	/**
	 * 针对表情的处理
	 *
	 * @param args
	 * @return
	 * @throws IOException
	 */
	private GroupFileInfo createGroupFileInfoCE(InteropFileMessageArgs args) throws IOException {
		LOGGER.info(String.format("createGroupFileInfoCE args=%s", args.toJsonObject()));
		GroupFileInfo fileInfo = new GroupFileInfo();

		fileInfo.setContentTransferEncoding("");

		String ceUrl = String.format("%s?id=%s", fetion_hds_url, args.getUrl());
		byte[] ceContent = FileDownloadHttpClient.getFileWithHeader(ceUrl);
		fileInfo.setThumbnail(ceContent);
		String fileType = FileTypeJudgeUtils.getFileTypeWithHeader(ceContent);
		fileInfo.setFileName(args.getUrl() + "." + fileType);
		MimeType type = MimeType.parse("image", fileType);
		String mimeFileType = type.getValue();
		fileInfo.setFileType(mimeFileType);
		fileInfo.setAcceptType(mimeFileType);
		fileInfo.setContent(null); // 如果是表情 则清理掉文件内容, 防止表情文件过大 带着到处跑...

		uploadGroupFileContent(fileInfo, fileType, ceContent);

		return fileInfo;
	}


	private String replaceUrl(String src) {
		if (src != null && src.contains("/ncfp/")) {
			//http://192.168.110.16:6020/ncfp/grpblockdownload?id=5162447266b059ba82029f18d342d82b&range=0-41615&c=feinno-userid:100426762
			return String.format("http://%s/%s", fetion_ncfp_path, src.substring(src.indexOf("ncfp/")));

		}
		return null;
	}

	/**
	 * 下载文件,上传到RCS 文件服务.
	 * 填充相关的GroupFileInfo 字段.
	 *
	 * @param fileInfo
	 * @param fileMimeType
	 * @param contentUrl
	 * @throws IOException
	 */
	private void uploadGroupFileContent(GroupFileInfo fileInfo, String fileMimeType, String contentUrl) throws IOException {
		byte[] bytes = FileDownloadHttpClient.getFile(contentUrl);
		FileStream stream = fileStreamService.create();
		stream.getOutputSteam().write(bytes);
		stream.setFileType(fileMimeType);
		stream.setFileSize(bytes.length);
		stream.flush();

		fileInfo.setMessageType(GroupMessageType.FILE);
		fileInfo.setContent(bytes);
		fileInfo.setFileSize(bytes.length);
		fileInfo.setTransferId(stream.getFileId());
		fileInfo.setFileRangeBegin(1);
		fileInfo.setFileRangeEnd(bytes.length);
	}

	private void uploadGroupFileContent(GroupFileInfo fileInfo, String fileMimeType, byte[] bytes) throws IOException {
		FileStream stream = fileStreamService.create();
		stream.getOutputSteam().write(bytes);
		stream.setFileType(fileMimeType);
		stream.setFileSize(bytes.length);
		stream.flush();

		fileInfo.setMessageType(GroupMessageType.FILE);
		fileInfo.setContent(bytes);
		fileInfo.setFileSize(bytes.length);
		fileInfo.setTransferId(stream.getFileId());
		fileInfo.setFileRangeBegin(1);
		fileInfo.setFileRangeEnd(bytes.length);
	}
}
